//////////////////////////////////////////////////////////////////////
//
//  CryEngine Source code
//	
//	File: AnimationManager.h
//  Implementation of Animation Manager.h
//
//	History:
//	January 12, 2005: Created by Ivo Herzeg <ivo@crytek.de>
//
//////////////////////////////////////////////////////////////////////

#ifndef _CRYTEK_CONTROLLER_MANAGER_HEADER_
#define _CRYTEK_CONTROLLER_MANAGER_HEADER_


#include "GlobalAnimationHeaderLMG.h"
#include "GlobalAnimationHeaderCAF.h"
#include "GlobalAnimationHeaderAIM.h"
#include "LoaderDBA.h"

class CAnimationSet;
class CryCGALoader;
class CAnimationManager;
class CAnimationSet;
struct CInternalSkinningInfo;



struct AnimSearchHelper {

	typedef std::vector<int> TIndexVector;
	typedef std::map<uint32 /*crc*/, TIndexVector* /*vector of indexes*/> TFoldersVector;

	TFoldersVector m_AnimationsMap;

	void AddAnimation(uint32 crc, uint32 gahIndex);
	void AddAnimation(const string& path, uint32 gahIndex);

	TIndexVector * GetAnimationsVector(uint32 crc);
	TIndexVector * GetAnimationsVector(const string& path);
	void Clear();

	~AnimSearchHelper() { Clear(); };
};


/////////////////////////////////////////////////////////////////////////////////////////////////////
// class CAnimationManager 
// Responsible for creation of multiple animations, subsequently bind to the character bones
// There is one instance of this class per a game.
/////////////////////////////////////////////////////////////////////////////////////////////////////
class CAnimationManager : public IAnimEvents
{
public:

	void StreamOnComplete (IReadStream* pStream, unsigned nError);
	//! Returns the number of installed anim-events for this asset
	int32 GetAnimEventsCount_CAF(int nGlobalID ) const; 
	int32 GetAnimEventsCount_CAF(const char* pFilePath );
	void AddAnimEvent_CAF(int nGlobalID, const char* pName, const char* pParameter, const char* pBone, float fTime, const Vec3& vOffset, const Vec3& vDir, const char* pModel);
	void AddAnimEvent_LMG(int nGlobalID, const char* pName, const char* pParameter, const char* pBone, float fTime, const Vec3& vOffset, const Vec3& vDir, const char* pModel);

	void InitialiseRunTimePools();
	void DestroyRunTimePools();

	void DeleteAllEventsForCAF(int nGlobalID);
	void DeleteAllEventsForLMG(int nGlobalID);

	int GetGlobalAnimID_CAF(const char* pFilePath);
	int GetGlobalAnimID_LMG(const char* pFilePath);

	// finds the animation by name. Returns -1 if no animation was found. Returns the animation ID if it was found
	int GetGlobalIDbyFilePath_CAF( const char* sFilePath );
	int GetGlobalIDbyFilePath_AIM( const char* sFilePath );
	int GetGlobalIDbyFilePath_LMG( const char* sFilePath );
	// create header with the specified name. If the header already exists, it return the index
	int CreateGAH_CAF( const string& strFileName );
	int CreateGAH_AIM( const string& strFileName );
	int CreateGAH_LMG( const string& strFileName );

	// loads existing animation record, returns false on error
	bool LoadAnimationTCB(int nGlobalAnimId, DynArray<CControllerTCB>& m_LoadCurrAnimation, CryCGALoader* pCGA, uint32 unique_model_id  );
		
	void UnloadAnimationCAF(GlobalAnimationHeaderCAF& rCAF);
	void UnloadAnimationAIM(int nGLobalAnimID);

	// returns the total number of animations hold in memory (for statistics)
	size_t GetGlobalAnimCount()  { return m_arrGlobalCAF.size();	}

	// notifies the controller manager that this client doesn't use the given animation any more.
	// these calls must be balanced with AnimationAddRef() calls
	void AnimationReleaseCAF( GlobalAnimationHeaderCAF& rCAF );
	void AnimationReleaseAIM( GlobalAnimationHeaderAIM& rAIM );
	void AnimationReleaseLMG( GlobalAnimationHeaderLMG& rLMG );

	// puts the size of the whole subsystem into this sizer object, classified, according to the flags set in the sizer
	void GetMemoryUsage(class ICrySizer* pSizer) const;	
	void DebugAnimUsage(uint32 printtxt);

	void Register (CAnimationSet* pClient)
	{
		m_arrClients.insert (std::lower_bound(m_arrClients.begin(), m_arrClients.end(), pClient), pClient);
	}
	void Unregister (CAnimationSet* pClient)
	{
		DynArray<CAnimationSet*>::iterator it = std::lower_bound(m_arrClients.begin(), m_arrClients.end(), pClient);
		if(it != m_arrClients.end() && *it == pClient)
			m_arrClients.erase (it);
		else
			assert (0); // the unregistered client tries to unregister
	}


	size_t GetSizeOfDBA();
	bool CreateGlobalHeaderDBA(DynArray<string>& name);
	bool DBA_PreLoad(const char* pFilePathDBA, bool highPriority);
	bool DBA_LockStatus(const char* pFilePathDBA, uint32 status, bool highPriority);
	bool DBA_Unload(const char* pFilePathDBA);
	bool DBA_Unload_All();
	bool Unload_All_Animation();
	int ReloadCAF(const char* szFilePathCAF);
	uint32 GetDBACRC32fromFilePath(const char* szFilePathCAF);
	bool IsDatabaseInMemory(uint32 nDBACRC32);

	DynArray<CGlobalHeaderDBA> m_arrGlobalHeaderDBA;
	CNameCRCMap		m_AnimationMapCAF;
	DynArray<GlobalAnimationHeaderCAF> m_arrGlobalCAF;
	//	CNameCRCMap		m_AnimationMapAIM;
	DynArray<GlobalAnimationHeaderAIM> m_arrGlobalAIM;
	//	CNameCRCMap		m_AnimationMapLMG;
	DynArray<GlobalAnimationHeaderLMG> m_arrGlobalLMG;

	// the sorted list of pointers to the clients that use the services of this manager
	DynArray<CAnimationSet*> m_arrClients;

	AnimSearchHelper m_animSearchHelper;
	SAnimMemoryTracker m_AnimMemoryTracker;

	bool m_shuttingDown;

	CAnimationManager(const CAnimationManager&);
	void operator=(const CAnimationManager&);

	CAnimationManager() : m_shuttingDown(false)
	{ 
		g_Alloc_AnimSelectProps = new stl::PoolAllocatorNoMT<sizeof(SAnimationSelectionProperties)>();
		//We reserve the place for future animations. 
		//The best performance will be archived when this number is >= actual number of animations that can be used, and not much greater
		m_arrGlobalHeaderDBA.reserve(100);
		m_arrGlobalCAF.reserve(0); 
		m_arrGlobalAIM.reserve(0);
		m_arrGlobalLMG.reserve(100);

		InitialiseRunTimePools();
	}

	~CAnimationManager()
	{
		m_shuttingDown=true;
		delete g_Alloc_AnimSelectProps;
		DestroyRunTimePools();
	}


private:

};													 


#endif
